#!/usr/bin/env python
# _*_ coding: utf-8 _*_
# @Time : 2021/4/25 4:25 下午
# @Author : sxt
# @Version：V 1.0
# @File : userauth.py
# @desc : 自定义的认证类
from typing import List

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

from app.models import UserToken
from threedGestureProject.common import tools

from pathtools.patterns import match_path as _match_path

from threedGestureProject.common.result import ResultCode


class Path:
    """
    路径, 包含路径和路径请求方法
    """

    def __init__(self, path: str, method: List[str] = None):
        self.path = path
        if method:
            self.method = [i.upper() for i in method]
        else:
            self.method = None


class UserAuth(BaseAuthentication):
    exclude_path = [
        Path('/user/login/'),
        Path('/course/', ['get']),
        Path('/courseType/', ['get']),
        Path('/user/register/'),
        Path('/userCheck/**'),
        Path('/admin/user/**'),
    ]

    def match_path(self, path: Path) -> bool:
        """
        匹配path
        :param path: 需要匹配的路径
        :return: 是否匹配成功
        """
        for _path in self.exclude_path:
            if _match_path(path.path, included_patterns=[_path.path, ]):
                method = _path.method
                if not method or path.method[0] in method:
                    return True
        return False

    def authenticate(self, request):
        print(request.path)
        # 被排除的path放行
        if self.match_path(Path(request.path, [request.method])):
            return None, None
        if request.method in ["GET", "POST", "PUT", "DELETE"]:
            # 获取随用户请求发来的token
            token = request.headers.get("Authorization")
            # 然后去数据库查询有没有这个token
            token_obj = UserToken.objects.filter(token=token).first()
            if token_obj and tools.certify_token(token=token):
                # 如果存在且token验证通过,以元组形式返回用户对象和token
                return token_obj.user, token
            else:
                # 不存在就直接抛错
                raise AuthenticationFailed("用户未登录或登录已失效", code=ResultCode.CODE_AUTH_ERROR)
